package com.tool.o2m.model;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author lunfy
 * @description:
 * @date 2024-06-24 10:27
 */
@Slf4j
public class UnderlineToCamelCaseRowMapper<T> implements RowMapper<T> {
    /** 匹配下划线及后一个字母的正则 */
    private static Pattern linePattern = Pattern.compile("_(\\w)");

    /** 缓存列名 */
    private static ConcurrentHashMap<String, String> columnCacheMap = new ConcurrentHashMap<>(200);

    private final Class<T> mappedClass;

    public UnderlineToCamelCaseRowMapper(Class<T> mappedClass) {
        this.mappedClass = mappedClass;
    }

    @Override
    public T mapRow(ResultSet rs, int rowNum) throws SQLException {
        ResultSetMetaData metaData = rs.getMetaData();
        Map<String, Object> rowData = new HashMap<>(128);
        for (int i = 1; i <= metaData.getColumnCount(); i++) {
            String columnName = metaData.getColumnName(i);
            String camelCaseName = underlineToCamelCase(columnName);
            rowData.put(camelCaseName, rs.getObject(columnName));
        }
        return JSON.parseObject(JSON.toJSONString(rowData), mappedClass);
    }

    /**
     * 下划线转驼峰
     *
     * @param input
     * @return
     */
    public static String underlineToCamelCase(String input) {
        // 统一转为小写，避免大小写敏感
        String underlineColumnName = input.toLowerCase();

        String camelCaseColumnName = columnCacheMap.get(underlineColumnName);
        if (StrUtil.isNotEmpty(camelCaseColumnName)) {
            return camelCaseColumnName;
        }

        Matcher matcher = linePattern.matcher(underlineColumnName);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
        }
        matcher.appendTail(sb);

        // 缓存
        columnCacheMap.put(underlineColumnName, sb.toString());
        return columnCacheMap.get(underlineColumnName);
    }

}
